﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpActionCut.h"

#include "IUserTransaction.h"
#include "IUiView.h"
#include "IHighlights.h"
#include "IPickFilter.h"
#include "IInstance.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IGraphicsNodeReference.h"
#include "ISelection.h"
#include "IPickTarget.h"
#include "NotificationUtils.h"
#include "CutUtils.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"

#include "IElementCut.h"

#include "IGroupSetting.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

CREATE_DEBUG_MODE_EXPORT(UseSubstractionBodyToCut, L"使用扣减体进行扣减", DebugModeGroup::DMGT_OTHERS, L"GDMPLab", L"2023-12-20"
    , L"默认情况下，使用实体扣减。如果打开此开关，则会使用扣减体进行扣减。");


namespace gcmp
{

    class GbmpCutToolPickFilter : public IPickFilter
    {
    public:
        GbmpCutToolPickFilter(gcmp::IDocument* pDocument);
        ~GbmpCutToolPickFilter(void);
        virtual bool AllowElement(const gcmp::ElementId& elementID) const override;
        virtual bool AllowGraphicsNode(const gcmp::IGraphicsNodeReference& nodeReference) const override;
        virtual bool SetPickTargetOption(gcmp::IPickTarget* pickTarget);
        void SetPickedNodeReferences(const gcmp::IGraphicsNodeReference& pickedNodeReference);
    protected:
        const IDocument* GetDocument() const { return m_pDocument; }

    private:
        const IDocument *m_pDocument;
        OwnerPtr<gcmp::IGraphicsNodeReference> m_pickedNodeReference; //过滤之前已经拾取到的对象，避免重复拾取
    };


    GbmpCutToolPickFilter::GbmpCutToolPickFilter(gcmp::IDocument* pDocument)
        : m_pDocument(pDocument)
        , m_pickedNodeReference(gcmp::IGraphicsNodeReference::Create())
    {
    }

    GbmpCutToolPickFilter::~GbmpCutToolPickFilter(void)
    {

    }

    bool GbmpCutToolPickFilter::AllowElement(const gcmp::ElementId& elementId) const
    {
        const IDocument* pDoc = GetDocument();
        if (!pDoc)
        {
            return false;
        }

        if (m_pickedNodeReference->GetElementId() == elementId)
        {
            return false;
        }

        // 非实体元素（模型线、参照平面、轴网、标高、视图范围框、立面视图标志、剖面视图标志）不支持扣减，拾取过滤掉
        if (IElement* pElement = pDoc->GetElement(elementId))
        {
            if (pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_MODEL_LINE ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_REFERENCE_PLANE ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_NEW_GRID ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_NEW_ELEVATION ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DEFAULT_VIEW_PORT ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_ELEVATION_VIEW_SYMBOL ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_SECTION_VIEW_SYMBOL_BORDER ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_SECTION_VIEW_SYMBOL ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_SECTION_VIEW_SYMBOL_LINE ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DIMENSION_TEXT ||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_DRAWING_VIEWPORT||
                pElement->GetBasicInformation()->GetCategoryUid() == BuiltInCategoryUniIdentities::BICU_GISTILE)
            {
                return false;
            }
        }

        return true;
    }

    bool GbmpCutToolPickFilter::AllowGraphicsNode(const gcmp::IGraphicsNodeReference& nodeReference) const
    {
        return false;
    }

    bool GbmpCutToolPickFilter::SetPickTargetOption(gcmp::IPickTarget* pickTarget)
    {
        pickTarget->DisableAll();
        pickTarget->EnableGraphicsElementShape();
        return true;
    }

    void GbmpCutToolPickFilter::SetPickedNodeReferences(const gcmp::IGraphicsNodeReference& pickedNodeReference)
    {
        m_pickedNodeReference->Set(pickedNodeReference);
    }
}

using namespace gcmp;

GbmpActionCut::GbmpActionCut()
    : m_isUserCancelled(false)
    , m_cutToolStatus(CUTTOOL_NOT_START)
{
}

GbmpActionCut::~GbmpActionCut()
{
    CleanupTempGraphicsShape();
}

void GbmpActionCut::InitAction(IUiView* pCurrentView)
{
    gcmp::IDocument* pDbDoc = GetDoc();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDbDoc != nullptr, L"pDbDoc指针为空",L"GDMPLab",L"2024-03-30");
    ISelection::Get()->Clear(pDbDoc);
    IHighlights::Get()->Clear();
    // 允许对组做扣减操作
    IGroupSetting* pGroupSetting = IGroupSetting::Get();
    if(pGroupSetting)
        pGroupSetting->SetSubElementSnapble(true);

    EnterPickFirstElementState();
}

void GbmpActionCut::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    switch (m_cutToolStatus)
    {
    case CUTTOOL_PICK_FIRST_ELEMENT:
        if (m_isUserCancelled)
        {
            CleanupTempGraphicsShape();
            MarkFinishStatus(ActionFinishStatus::Successful);
            return;
        }

        if (m_nodeReferencesFirst.size() > 0 && m_nodeReferencesFirst.at(0)->IsValid())
        {
            IHighlights::Get()->SetGraphicsNodeReferences(m_nodeReferencesFirst);
            EnterPickSecondElementState();
        }
        else
        {
            EnterPickFirstElementState();
        }
        break;
    case CUTTOOL_PICK_SECOND_ELEMENT:
        CleanupTempGraphicsShape();
        if (m_isUserCancelled)
        {
            IHighlights::Get()->Clear();

            IGroupSetting* pGroupSetting = IGroupSetting::Get();
            if (pGroupSetting)
                pGroupSetting->SetSubElementSnapble(false);
            
            MarkFinishStatus(ActionFinishStatus::Successful);
            return;
        }
        else
        {
            if (m_nodeReferencesSecond.size() > 0 && m_nodeReferencesSecond.at(0)->IsValid())
            {
                IHighlights::Get()->SetGraphicsNodeReferences(m_nodeReferencesFirst);
                CutElement(pCurrentView->GetModelView());
            }
            EnterPickSecondElementState();
        }
        break;
    default:
        break;
    }
    MarkFinishStatus(ActionFinishStatus::Successful);
}

void GbmpActionCut::EnterPickFirstElementState()
{
    m_cutToolStatus = CUTTOOL_PICK_FIRST_ELEMENT;
    m_isUserCancelled = false;
    OnSetPromptMsg(m_cutToolStatus);
    OnSetCursorType(m_cutToolStatus);
    gcmp::OwnerPtr<IPickFilter> opCutToolPickFilter;
    opCutToolPickFilter = TransferOwnership(NEW_AS_OWNER_PTR(GbmpCutToolPickFilter, GetDoc()));
    PickNodeReferenceExchangeData exchangeData(true, &m_nodeReferencesFirst, &m_isUserCancelled);
    PickNodeReferenceOption pickOption;
    pickOption.SetCursorType(GetCursorType());
    gcmp::OwnerPtr<IAction> upPickNodeReferenceAction = IPickNodeReferenceAction::Create(exchangeData, TransferOwnership(opCutToolPickFilter), pickOption);
    StartChildAction(TransferOwnership(upPickNodeReferenceAction));
}

void GbmpActionCut::EnterPickSecondElementState()
{
    m_cutToolStatus = CUTTOOL_PICK_SECOND_ELEMENT;
    m_isUserCancelled = false;
    OnSetPromptMsg(m_cutToolStatus);
    OnSetCursorType(m_cutToolStatus);
    gcmp::OwnerPtr<GbmpCutToolPickFilter> opCutToolPickFilter(NEW_AS_OWNER_PTR(GbmpCutToolPickFilter, GetDoc()));
    opCutToolPickFilter->SetPickedNodeReferences(*m_nodeReferencesFirst.at(0));
    PickNodeReferenceOption pickOption;
    pickOption.SetCursorType(GetCursorType());
    gcmp::OwnerPtr<IAction> opPickNodeReferenceAction = IPickNodeReferenceAction::Create(
        PickNodeReferenceExchangeData(true, &m_nodeReferencesSecond, &m_isUserCancelled),
        TransferOwnership(opCutToolPickFilter),
        pickOption
    );
    StartChildAction(TransferOwnership(opPickNodeReferenceAction));
}


void GbmpActionCut::CutElement(gcmp::IModelView* pModelView) const
{
    IDocument* pDoc = GetDoc();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_nodeReferencesFirst.size() > 0 && m_nodeReferencesFirst.at(0) && m_nodeReferencesFirst.at(0)->IsValid() && m_nodeReferencesSecond.size() > 0 && m_nodeReferencesSecond.at(0) && m_nodeReferencesSecond.at(0)->IsValid(), L"拾取到的GNodeReferences数量不为2",L"GDMPLab",L"2024-03-30");

    ElementId cutterId = m_nodeReferencesFirst.at(0)->GetElementId();
    ElementId cutteeId = m_nodeReferencesSecond.at(0)->GetElementId();

    IElement* pCutter = pDoc->GetElement(cutterId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCutter != nullptr, L"pCutter为空",L"GDMPLab",L"2024-03-30");
    IElement* pCuttee = pDoc->GetElement(cutteeId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pCuttee != nullptr, L"pCuttee为空",L"GDMPLab",L"2024-03-30");
    bool isUseSubstractionBodyToCut = DEBUG_MODE(UseSubstractionBodyToCut);
    
    if (CutUtils::IsGraphicsShapeIntersect(pDoc, pCutter, pCuttee, isUseSubstractionBodyToCut))
    {
        OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(GetDoc(), GBMP_TR(L"扣减"));
        DBG_WARN_AND_RETURN_VOID_UNLESS(ut, L"ut为空",L"GDMPLab",L"2024-03-30");

        IElementCut::Create(pDoc, cutterId, cutteeId, isUseSubstractionBodyToCut);
        ut->Commit();
    }
    else
    {
        NotificationUtils::PostNotification(NotificationTypes::WarningNotificationType, GBMP_TR(L"两个构件不相交，无法建立扣减关系。"));
    }
}


void GbmpActionCut::OnSetPromptMsg(EnCutToolStatus tmes)
{
    switch (tmes)
    {
    case CUTTOOL_PICK_FIRST_ELEMENT:
        SetPromptMessage(GBMP_TR(L"选择扣减参考对象"));
        break;
    case CUTTOOL_PICK_SECOND_ELEMENT:
        SetPromptMessage(GBMP_TR(L"选择被扣减的对象"));
        break;
    }
}

void GbmpActionCut::OnSetCursorType(EnCutToolStatus /*tmes*/)
{
    SetCursorType(CursorType::ArrowCursor);
}
